package com.wex.jni;

public class JniFFmpeg {

    static {
        System.loadLibrary("ffjni");
    }

    static public int Type_Encode = 0;
    static public int Type_Decode = 1;

    static public int Format_H264 = 0;
    static public int Format_H265 = 1;

    static public native String ffjniInfo();

    static public native long codecOpen(int type, int format, int width, int height, int fps);
    static public native int codecClose(long fd);

    static public native int codecPush(long fd, byte[] data);
    static public native byte[] codecGain(long fd);

    /*
     *  用于h26x数据解码前的帧截取
     *  使用Set()传入带解码数据流,用Get()截取单帧包
     */
    static public class H26xFiFo {
        private byte[] buff = null;
        private int buffSize = 0;
        private int headLen = 0;
        private int tailLen = 0;

        /*
         *  frameSize: 一帧数据量(1080P建议 1024*800 字节, 480P建议 1024*500 字节)
         *  frameCount: 缓存帧数量
         */
        public H26xFiFo(int frameSize, int frameCount) {
            buffSize = frameSize * frameCount;
            buff = new byte[buffSize];
            headLen = 0;
            tailLen = buffSize;
        }

        /*
         *  数据缺口,即当前可以入栈数据量
         *  通过先判断该值再决定是否要读取文件,以防止数据无处安放
         */
        public int Gaps() {
            return tailLen;
        }

        /*
         *  送入H26x数据
         */
        public boolean Set(byte[] dat, int datLen) {
            //尾部不足以入栈当前包
            if (tailLen < datLen)
                return false;
            synchronized(this) {
                System.arraycopy(dat, 0, buff, headLen, datLen);
                tailLen -= datLen;
                headLen = buffSize - tailLen;
            }
            return true;
        }

        /*
         *  取出H26x帧
         */
        public byte[] Get() {
            //缓冲区没有足够解析用的数据量
            if (headLen < 8)
                return null;
            byte[] retBuff = null;
            synchronized(this) {
                int index = -1;
                int index2 = -1;
                //一次检索 001 或者 0001
                int i = 0;
                for (; i < headLen - 3; i++) {
                    if (buff[i] == 0 && buff[i + 1] == 0 && (buff[i + 2] == 1 || (buff[i + 2] == 0 && buff[i + 3] == 1))) {
                        index = i;
                        i += 3;
                        break;
                    }
                }
                //二次检索 001 或者 0001
                for (;i < headLen - 3; i++) {
                    if (buff[i] == 0 && buff[i + 1] == 0 && (buff[i + 2] == 1 || (buff[i + 2] == 0 && buff[i + 3] == 1))) {
                        index2 = i;
                        break;
                    }
                }
                //有截取到数据,提取数据,然后移位
                if (index2 > index) {
                    //提取数据
                    int retByteSize = index2 - index;
                    retBuff = new byte[retByteSize];
                    System.arraycopy(buff, index, retBuff, 0, retByteSize);
                    //移位
                    for (index = 0; index2 < headLen; index++, index2++)
                        buff[index] = buff[index2];
                    //更新缓冲区信息
                    headLen = index;
                    tailLen = buffSize - headLen;
                }
                else {
                    //没有检索到头部,舍弃所有数据
                    if (index < 0) {
                        //更新缓冲区信息
                        headLen = 0;
                        tailLen = buffSize;
                    }
                    //找到头没找到尾,不移位(保持现状)
                    else {
                        ;
                    }
                }
            }
            return retBuff;
        }
    }
}
